package org.gcoat.list;

import java.util.Arrays;

public class SpineLongList implements LongList {
	private static final int DEFAULT_SHIFT = 5;
	private final int shift_;
	private int size_;
	private long[][] spine_;

	public SpineLongList() {
		shift_ = DEFAULT_SHIFT;
		spine_ = new long[1][1 << shift_];
	}

	void rangeCheck(int index) {
		if (index < 0 || index >= size_) {
			throw new IndexOutOfBoundsException("index = " + index + "; size = " + size_);
		}
	}

	@Override
	public int size() {
		return size_;
	}

	@Override
	public long get(int index) {
		rangeCheck(index);
		long[] array = spine_[index >>> shift_];
		return array[index & (array.length - 1)];
	}

	@Override
	public long set(int index, long value) {
		rangeCheck(index);
		long[] array = spine_[index >>> shift_];
		int normi = index & (array.length - 1);
		long res = array[normi];
		array[normi] = value;
		return res;
	}

	@Override
	public void add(long value) {
		int findex = size_ >>> shift_;
		if (spine_.length == findex) {
			int len = spine_.length;
			spine_ = Arrays.copyOf(spine_, len + (len >> 1) + 1);
		}
		long[] array = spine_[findex];
		if (array == null) {
			array = new long[1 << shift_];
			spine_[findex] = array;
		}
		array[size_ & (array.length - 1)] = value;
		++size_;
	}

	@Override
	public void clear() {
		size_ = 0;
	}

	public void trimToSize() {
		int fsize = (size_ + (1 << shift_) - 1) >> shift_;
		if (spine_.length != fsize) {
			spine_ = Arrays.copyOf(spine_, fsize);
		}
	}
}
